home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / aminet / dev / lang / pcq12src.lzh / Source / IO.p < prev    next >
Text File  |  1991-04-19  |  23KB  |  1,129 lines

  1. External;
  2.  
  3. {
  4.     IO.p (of PCQ Pascal)
  5.     Copyright (c) 1989 Patrick Quaid
  6.  
  7.     This module handles the IO of the compiler.  The actual
  8. compilation of the io statements is handled in stanprocs.p
  9. }
  10.  
  11. {$O-}
  12. {$I "Pascal.i"}
  13. {$I "Include:Libraries/DOS.i" }
  14. {$I "Include:Utils/StringLib.i"}
  15. {$I "Include:Utils/Break.i"}
  16.  
  17.  
  18.     Procedure Out_Operation1(op : OpCodes; Size : Byte;
  19.                     EA : EAModes; Reg : Regs);
  20.         External;
  21.     Procedure Out_Extension(Ext : Integer);
  22.         External;
  23.  
  24. Function EndOfFile() : Boolean;
  25.  
  26. {
  27.     This just determines when the end of all input has occured.
  28. }
  29.  
  30. begin
  31.     EndOfFile := (InFile = nil) and (not CharBuffed);
  32. end;
  33.  
  34. Procedure AnnounceFile;
  35. begin
  36.     if StdOut_Interactive then
  37.     Write('\r\cK', LineNo:5, ' ', InFile^.Name, '\r');
  38. end;
  39.  
  40. Procedure WriteLineNo;
  41. begin
  42.     if StdOut_Interactive then
  43.     Write(Chr(13), LineNo:5);
  44. end;
  45.  
  46. Procedure CountLines;
  47.  
  48. { Does the bookkeeping for errors }
  49.  
  50. begin
  51.     if CurrentChar = Chr(10) then begin
  52.     LineNo := Succ(LineNo);
  53.     if Inform then
  54.         if (LineNo and 15) = 0 then
  55.         WriteLineNo;
  56.     end;
  57. end;
  58.  
  59. Procedure EndComment;
  60.     forward;    { It's in this module }
  61.  
  62. Procedure CloseInputFile;
  63.  
  64. { This closes the current input file and restores the saved stuff }
  65.  
  66. var
  67.     TempPtr : FileRecPtr;
  68.     Result  : Short;
  69. begin
  70.     if Inform and StdOut_Interactive then begin
  71.     WriteLineNo;
  72.     Writeln;
  73.     end;
  74.     Close(InFile^.PCQFile);
  75.     Result := IOResult;
  76.     TempPtr := InFile^.Previous;
  77.     FreeString(InFile^.Name);
  78.     Dispose(InFile);
  79.     InFile := TempPtr;
  80.     if InFile <> nil then begin
  81.     LineNo := InFile^.SaveLine;
  82.     FNStart := InFile^.SaveStart;
  83.     CurrentChar := InFile^.SaveChar;
  84.     if Inform then
  85.         AnnounceFile;
  86.     EndComment;
  87.     end else
  88.     CurrentChar := Chr(0);
  89. end;
  90.  
  91. Procedure Abort;
  92.  
  93. {
  94.     This routine cuts out cleanly.  If you are debugging the
  95. compiler, this is a likely place to put post mortem dumps, like the
  96. one commented out.
  97. }
  98. var
  99.     Result : Short;
  100. begin
  101.     While InFile <> nil do
  102.     CloseInputFile;
  103.     Close(OutFile);
  104.     Result := IOResult;
  105.     Writeln('Compilation Aborted');
  106.     Exit(20);
  107. end;
  108.  
  109. Function OpenInputFile(name : String) : Boolean;
  110.  
  111. { This routine opens a new file record, and a new file.  It also
  112.   saves the state of the File-dependant variables, like LineNo. }
  113.  
  114. var
  115.     TempPtr : FileRecPtr;
  116.     OpenError : Integer;
  117. begin
  118.     New(TempPtr);
  119.     if not ReOpen(name, TempPtr^.PCQFile, 10240) then begin
  120.     Dispose(TempPtr);
  121.     OpenError := IOResult;
  122.     OpenInputFile := False;
  123.     end;
  124.     TempPtr^.Previous := InFile;
  125.     if InFile <> nil then begin
  126.     InFile^.SaveLine := LineNo;
  127.     InFile^.SaveStart := FNStart;
  128.     InFile^.SaveChar  := CurrentChar;
  129.     end;
  130.     LineNo := 1;
  131.     FNStart := 1;
  132.     TempPtr^.Name := strdup(name);
  133.     InFile := TempPtr;
  134.     if EOF(InFile^.PCQFile) then
  135.     CloseInputFile
  136.     else
  137.     Read(Infile^.PCQFile, CurrentChar);
  138.     if Inform then
  139.     AnnounceFile;
  140.     OpenInputFile := True;
  141. end;
  142.  
  143. Function EQFix(x : Short) : Integer;
  144.  
  145. {
  146.     This helps implement a queue.  In this case it's for the
  147. error queue.
  148. }
  149.  
  150. begin
  151.     EQFix := x and EQSize;
  152. end;
  153.  
  154. Procedure Error(ptr : string);
  155.  
  156. {
  157.     This just writes out at most the previous 128 characters or
  158. two lines, then writes the error message passed to it.  If there
  159. are five errors, it aborts.
  160. }
  161.  
  162. var
  163.     index : integer;
  164.     newlines : integer;
  165.     Column : Short;
  166.     LessLines : Short;
  167. begin
  168.     index     := EQEnd;
  169.     newlines  := 0;
  170.     Column    := 0;
  171.     LessLines := 0;
  172.  
  173.     while (index <> EQStart) and (newlines < 2) do begin
  174.     if Index = ErrorPtr then begin
  175.         Column := 1;
  176.         LessLines := NewLines;
  177.     end else if LessLines = NewLines then
  178.         Inc(Column);
  179.  
  180.     index := EQFix(index - 1);
  181.     if ErrorQ[EQFix(index - 1)] = chr(10) then
  182.         Inc(NewLines);
  183.     end;
  184.  
  185.     if CurrentChar = Chr(10) then
  186.     Inc(LessLines);
  187.  
  188.     if Inform then begin
  189.     if StdOut_Interactive then
  190.         write('\n\cK'); { newline, ClrEOL }
  191.     while index <> EQEnd do begin
  192.         if (index = ErrorPtr) and StdOut_Interactive then
  193.         write('\c0;33;40m');  { start highlight for ANSI }
  194.         write(ErrorQ[index]);
  195.         index := EQFix(index + 1);
  196.     end;
  197.     if StdOut_Interactive then
  198.         write('\c0;31;40m');  { end highlight }
  199.     writeln;
  200.     write('Line ', LineNo - LessLines, ' ');
  201.     if currfn <> nil then
  202.         write('(', CurrFn^.Name, ')');
  203.     writeln(': ', ptr, '\n');
  204.     end else
  205.     Writeln('"', InFile^.Name, '" At ', LineNo - LessLines, ',',
  206.         Column, ' : ', ptr);
  207.                  { Quiet mode, no surprises }
  208.  
  209.     Inc(errorcount);
  210.     if errorcount > 3 then
  211.     Abort;
  212.     if CheckBreak() then
  213.     Abort;
  214.     if Inform then
  215.     AnnounceFile;
  216. end;
  217.  
  218. Procedure ReadChar;
  219.  
  220. { This is the main link between the lexical analysis stuff and the
  221.   IO stuff.  It sets up CurrentChar and keeps the line count. }
  222. var
  223.     IOError : Integer;
  224. begin
  225.     if CheckBreak() then
  226.     Abort;
  227.     if CharBuffed then begin
  228.     CurrentChar := BuffedChar;
  229.     CharBuffed := False;
  230.     return;
  231.     end;
  232.     if EOF(InFile^.PCQFile) then
  233.     CloseInputFile
  234.     else begin
  235.     Read(InFile^.PCQFile, CurrentChar);
  236.     IOError := IOResult;
  237.     CountLines;
  238.     end;
  239.     EQEnd := EQFix(Succ(EQEnd));
  240.     ErrorQ[EQEnd] := CurrentChar;
  241.     if EQStart = EQEnd then
  242.     EQStart := EQFix(Succ(EQStart));
  243. end;
  244.  
  245. Function NextChar() : Char;
  246. var
  247.     c : Char;
  248. begin
  249.     if not CharBuffed then begin
  250.     c := CurrentChar;
  251.     ReadChar;
  252.     BuffedChar := CurrentChar;
  253.     CurrentChar := c;
  254.     CharBuffed := True;
  255.     end;
  256.     NextChar := BuffedChar;
  257. end;
  258.  
  259. Procedure EndComment;
  260.  
  261. {
  262.     This just eats characters up to the end of a comment.  If
  263. you want nested comments, this is probably the place to do it.
  264. }
  265.  
  266. begin
  267.     while (Currentchar <> '}') and (not EndOfFile()) do
  268.     ReadChar;
  269.     if not EndOfFile() then
  270.     ReadChar;
  271. end;
  272.  
  273. Function GetLabel() : integer;
  274.  
  275. {
  276.     As in all compilers, this just returns a unique serial
  277. number.
  278. }
  279.  
  280. begin
  281.     Inc(NxtLab);
  282.     getlabel := nxtlab;
  283. end;
  284.  
  285. Procedure PrintLabel(lab : integer);
  286.  
  287. {
  288.     This routine prints a label based on a number from the
  289. above procedure.  The prefix for the label can be anything the
  290. assembler accepts - in this case I wanted it similar to the prefix
  291. of the run time library routines.  I didn't realize how ugly it
  292. would look.
  293. }
  294.  
  295. begin
  296.     write(OutFile, '_p%', lab);
  297. end;
  298.  
  299. Function JustFileName(S : String) : String;
  300.  
  301. { returns a string that is the file name part of a path.  It does
  302.   NOT allocate space. }
  303.  
  304. var
  305.     Ptr : String;
  306. begin
  307.     if S^ = Chr(0) then
  308.     JustFileName := S;
  309.     Ptr := S;
  310.     while Ptr^ <> Chr(0) do
  311.     Inc(Ptr);
  312.     Dec(Ptr);
  313.     while (Ptr^ <> ':') and (Ptr^ <> '/') do begin
  314.     if Ptr = S then
  315.         JustFileName := S;
  316.     Dec(Ptr);
  317.     end;
  318.     Inc(Ptr);
  319.     JustFileName := Ptr;
  320. end;
  321.  
  322. Procedure AddIncludeName(S : String);
  323.  
  324. { Adds the name of an include file to the list, so it won't be
  325.   included again. }
  326.  
  327. var
  328.     Ptr : IncludeRecPtr;
  329. begin
  330.     Ptr := IncludeRecPtr(AllocString(strlen(S) + 5));
  331.     if Ptr = nil then
  332.     Abort;
  333.     strcpy(Adr(Ptr^.Name), S);
  334.     Ptr^.Next := IncludeList;
  335.     IncludeList := Ptr;
  336. end;
  337.  
  338. Function AlreadyIncluded(S : String) : Boolean;
  339.  
  340. { Determines whether a file has been included already }
  341.  
  342. var
  343.     Ptr : IncludeRecPtr;
  344. begin
  345.     Ptr := IncludeList;
  346.     while Ptr <> nil do begin
  347.     if strieq(Adr(Ptr^.Name), S) then
  348.         AlreadyIncluded := True;
  349.     Ptr := Ptr^.Next;
  350.     end;
  351.     AlreadyIncluded := False;
  352. end;
  353.  
  354. Procedure DoInclude;
  355.  
  356. {
  357.     The name says it all.  The mechanics of the include
  358. directive are all handled here.
  359. }
  360.  
  361. var
  362.     Ptr : String;
  363. begin
  364.     ReadChar;
  365.     While (CurrentChar <= ' ') and (not EndOfFile()) do
  366.     ReadChar;
  367.     if CurrentChar <> '"' then begin
  368.     Error("Missing Quote");
  369.     EndComment;
  370.     Return;
  371.     end;
  372.     ReadChar;
  373.     Ptr := SymText;
  374.     while CurrentChar <> '"' do begin
  375.     Ptr^ := CurrentChar;
  376.     Inc(Ptr);
  377.     if EndOfFile() then
  378.         Return;
  379.     ReadChar;
  380.     end;
  381.     Ptr^ := Chr(0); { mark then end of the file name }
  382.     ReadChar;        { read the end quote }
  383.     if not AlreadyIncluded(JustFileName(SymText)) then begin
  384.     if OpenInputFile(SymText) then
  385.         AddIncludeName(JustFileName(SymText))
  386.     else begin
  387.         Error("Could not open input file");
  388.         EndComment;
  389.     end;
  390.     end else
  391.     EndComment;
  392. end;
  393.  
  394. Procedure DoComment;
  395.  
  396. {
  397.     This routine implements compiler directives.
  398. }
  399.  
  400.     Procedure DoASM;
  401.     var
  402.     Buffer : Array [0..127] of Char;
  403.     i      : Byte;
  404.  
  405.     Procedure WriteIt;
  406.     begin
  407.         Buffer[i] := '\0';
  408.         Out_Operation1(op_LABEL,3,ea_String,a7);
  409.         Out_Extension(Integer(strdup(Adr(Buffer))));
  410.         i := 0;
  411.     end;
  412.  
  413.     begin
  414.     ReadChar;
  415.     i := 0;
  416.     while CurrentChar <> '}' do begin
  417.         if (CurrentChar = Chr(10)) and (i > 0) then
  418.         WriteIt
  419.         else begin
  420.         Buffer[i] := CurrentChar;
  421.         Inc(i);
  422.         if i > 127 then
  423.             WriteIt;
  424.         end;
  425.  
  426.         if EndOfFile() then begin
  427.         Error("File ended in a comment");
  428.         return;
  429.         end;
  430.         ReadChar;
  431.     end;
  432.     if i > 0 then
  433.         WriteIt;
  434.     ReadChar;
  435.     end;
  436.  
  437.     Procedure DoOnOff(var Flag : Boolean);
  438.     begin
  439.     ReadChar;
  440.     if CurrentChar = '+' then
  441.         Flag := True
  442.     else if CurrentChar = '-' then
  443.         Flag := False;
  444.     end;
  445.  
  446.     Procedure DoStorage;
  447.     var
  448.     KillChar : Boolean;
  449.     begin
  450.     ReadChar;
  451.     KillChar := True;
  452.     case CurrentChar of
  453.       'X' : StandardStorage := st_external;
  454.       'P' : StandardStorage := st_private;
  455.       'N' : StandardStorage := st_internal;
  456.     else begin
  457.         Error("Unknown storage class");
  458.         KillChar := False;
  459.          end;
  460.     end;
  461.     if KillChar then
  462.         ReadChar;
  463.     end;
  464.  
  465. begin
  466.     readchar;
  467.     if currentchar = '$' then begin
  468.     repeat
  469.         readchar; { either $ or , }
  470.         Case CurrentChar of
  471.           'I' : if (NextChar = '+') or (NextChar = '-') then
  472.             DoOnOff(IOCheck)
  473.             else begin
  474.             DoInclude;
  475.             return;
  476.             end;
  477.           'A' : begin
  478.             DoASM;
  479.             return;
  480.             end;
  481.           'R' : DoOnOff(RangeCheck);
  482.           'O' : DoOnOff(IOCheck);
  483.           'S' : DoStorage;
  484.           'B' : DoOnOff(ShortCircuit);
  485.         else begin
  486.             Error("Unknown Directive");
  487.             EndComment;
  488.             return;
  489.          end;
  490.         end;
  491.         if (CurrentChar <> ',') or EndOfFile then begin
  492.         EndComment;
  493.         return;
  494.         end;
  495.     until false;
  496.     end else
  497.     EndComment;
  498. end;
  499.  
  500. Function Alpha(c : char): boolean;
  501.  
  502. {
  503.     This function answers the eternal question "is this
  504. character an alphabetic character?"  Note that _ is.
  505. }
  506.  
  507. begin
  508.     c := toupper(c);
  509.     Alpha := ((c >= 'A') and (c <= 'Z')) or (c = '_');
  510. end;
  511.  
  512. Function AlphaNumeric(c : char): boolean;
  513.  
  514. {
  515.     Is the character a letter or digit?
  516. }
  517.  
  518. begin
  519.     AlphaNumeric := Alpha(c) or isdigit(c);
  520. end;
  521.  
  522. Procedure Header;
  523.  
  524. {
  525.     This routine references all the run time library routines.
  526. One thing I like about A68k is that the only routines that are
  527. used in the assembly code end up in the object file.  Maybe all
  528. assemblers do it, but I don't know.
  529. }
  530.  
  531. begin
  532.     writeln(OutFile, "* Pascal compiler intermediate assembly program.\n\n");
  533.     writeln(OutFile, "\tSECTION\tPCQMain\n");
  534.     writeln(OutFile, "\tXREF\t_Input");
  535.     writeln(OutFile, "\tXREF\t_Output");
  536.     writeln(OutFile, "\tXREF\t_p%WriteInt");
  537.     writeln(OutFile, "\tXREF\t_p%WriteReal");
  538.     writeln(OutFile, "\tXREF\t_p%WriteChar");
  539.     writeln(OutFile, "\tXREF\t_p%WriteBool");
  540.     writeln(OutFile, "\tXREF\t_p%WriteCharray");
  541.     writeln(OutFile, "\tXREF\t_p%WriteString");
  542.     writeln(OutFile, "\tXREF\t_p%WriteLn");
  543.     writeln(OutFile, "\tXREF\t_p%ReadInt");
  544.     writeln(OutFile, "\tXREF\t_p%ReadReal");
  545.     writeln(OutFile, "\tXREF\t_p%ReadCharray");
  546.     writeln(OutFile, "\tXREF\t_p%ReadChar");
  547.     writeln(OutFile, "\tXREF\t_p%ReadString");
  548.     writeln(OutFile, "\tXREF\t_p%ReadLn");
  549.     writeln(OutFile, "\tXREF\t_p%ReadArb");
  550.     writeln(OutFile, '\tXREF\t_p%FilePtr');
  551.     writeln(OutFile, '\tXREF\t_p%Get');
  552.     writeln(OutFile, '\tXREF\t_p%Put');
  553.     writeln(OutFile, "\tXREF\t_p%dispose");
  554.     writeln(OutFile, "\tXREF\t_p%new");
  555.     writeln(OutFile, "\tXREF\t_p%Open");
  556.     writeln(OutFile, "\tXREF\t_p%OpenB");
  557.     writeln(OutFile, "\tXREF\t_p%WriteArb");
  558.     writeln(OutFile, "\tXREF\t_p%Close");
  559.     writeln(OutFile, "\tXREF\t_p%exit");
  560.     writeln(OutFile, "\tXREF\t_p%lmul");
  561.     writeln(OutFile, "\tXREF\t_p%ldiv");
  562.     writeln(OutFile, "\tXREF\t_p%lrem");
  563.     writeln(OutFile, "\tXREF\t_p%MathBase");
  564.     writeln(OutFile, '\tXREF\t_p%sin');
  565.     writeln(OutFile, '\tXREF\t_p%cos');
  566.     writeln(OutFile, '\tXREF\t_p%sqrt');
  567.     Writeln(OutFile, '\tXREF\t_p%tan');
  568.     Writeln(OutFile, '\tXREF\t_p%atn');
  569.     Writeln(OutFile, '\tXREF\t_p%ln');
  570.     Writeln(OutFile, '\tXREF\t_p%exp');
  571.     Writeln(OutFile, '\tXREF\t_p%CheckIO');
  572.     Writeln(OutFile, '\tXREF\t_p%CheckRange\n');
  573.     if mainmode then begin
  574.     if SmallInitialize then begin
  575.         Writeln(OutFile, '\tXREF\t_p%minimal_init');
  576.         Writeln(OutFile, "\tjsr\t_p%minimal_init");
  577.     end else begin
  578.         writeln(OutFile, "\tXREF\t_p%initialize");
  579.         writeln(OutFile, "\tjsr\t_p%initialize");
  580.     end;
  581.     writeln(OutFile, "\tjsr\t_MAIN");
  582.     writeln(OutFile, '\tmoveq\t#0,d0');
  583.     writeln(OutFile, "\tjsr\t_p%exit");
  584.     writeln(OutFile, "\trts");
  585.     end
  586. end;
  587.  
  588. Procedure Trailer;
  589.  
  590. {
  591.     This routine is the most important in the compiler
  592. }
  593.  
  594. begin
  595.     writeln(OutFile, "\tEND");
  596. end;
  597.  
  598. Procedure Blanks;
  599.  
  600. {
  601.     blanks() skips spaces, tabs and eoln's.  It handles
  602. comments if it comes across one.
  603. }
  604.  
  605. var
  606.     done : boolean;
  607. begin
  608.     while ((CurrentChar <= ' ') or (CurrentChar = '{')) and
  609.       (not EndOfFile()) do begin
  610.     if CurrentChar = '{' then
  611.         DoComment
  612.     else
  613.         ReadChar;
  614.     end;
  615. end;
  616.  
  617. Procedure DumpLitQ(k : Integer);
  618.  
  619. {
  620.     This procedure dumps the literal table at the end of the
  621. compilation.  Individual components are referenced as offsets to
  622. the literal label.
  623. }
  624.  
  625. var
  626.     j        : integer;
  627.     quotemode    : boolean;
  628. begin
  629.     while k < litptr do begin
  630.     write(OutFile, "\tdc.b\t");
  631.     j := 0;
  632.     quotemode := false;
  633.     while j < 40 do begin
  634.         if (ord(litq[k]) > 31) and (ord(litq[k]) <> 39) then begin
  635.         if quotemode then
  636.             write(OutFile, litq[k])
  637.         else begin
  638.             if j > 0 then
  639.             write(OutFile, ',');
  640.             write(OutFile, chr(39), litq[k]);
  641.             quotemode := true;
  642.         end;
  643.         end else begin
  644.         if quotemode then begin
  645.             write(OutFile, chr(39));
  646.             quotemode := false;
  647.         end;
  648.         if j > 0 then
  649.             write(OutFile, ',');
  650.         write(OutFile, ord(litq[k]));
  651.         if j > 32 then
  652.             j := 40
  653.         else
  654.             j := j + 3;
  655.         end;
  656.         j := j + 1;
  657.         k := k + 1;
  658.         if k >= litptr then
  659.         j := 40;
  660.     end;
  661.     if quotemode then
  662.         write(OutFile, chr(39));
  663.     writeln(OutFile);
  664.     end
  665. end;
  666.  
  667. Procedure DumpLits;
  668. begin
  669.     if LitPtr = 0 then
  670.     return;
  671.     writeln(OutFile, '\n\tSECTION\tLITS,DATA');
  672.     PrintLabel(LitLab);
  673.     DumpLitQ(0);
  674. end;
  675.  
  676. Procedure DumpIds;
  677.  
  678. {
  679.     This routine does whatever is appropriate with the various
  680. identifers.  If it's a global, it either references it or allocates
  681. space.  Similar stuff for the other ids.  When the modularity of
  682. PCQ is better defined, this routine will have to do more work.
  683. }
  684.  
  685. var
  686.     CB        : BlockPtr;
  687.     ID        : IDPtr;
  688.     TP        : TypePtr;
  689.     i        : Integer;
  690.     isodd    : boolean;
  691.     WroteSection : Boolean;
  692. begin
  693.     WroteSection := False;
  694.     isodd := false;
  695.     CB := CurrentBlock;
  696.     while CB <> nil do begin
  697.     for i := 0 to Hash_Size do begin
  698.         ID := CB^.Table[i];
  699.         while ID <> nil do begin
  700.         case ID^.Object of
  701.           global : case ID^.Storage of
  702.                 st_internal,
  703.                 st_private  : begin
  704.                         if not WroteSection then begin
  705.                         writeln(OutFile, "\n\tSECTION\tSTORAGE,BSS\n");
  706.                         WroteSection := True;
  707.                         end;
  708.                         TP := ID^.VType;
  709.                         if isodd and (TP^.Size > 1) then begin
  710.                         Writeln(OutFile, "\tCNOP\t0,2");
  711.                         isodd := False;
  712.                         end;
  713.                         if ID^.Storage <> st_private then
  714.                         Writeln(OutFile,"\tXDEF\t_", ID^.Name);
  715.                         Write(OutFile, '_', ID^.Name);
  716.                         Writeln(OutFile, "\tds.b\t", TP^.Size);
  717.                         if odd(TP^.Size) then
  718.                         isodd := not isodd;
  719.                       end;
  720.                end;
  721.           proc,
  722.           func  : if ID^.Storage = st_forward then
  723.                 Writeln(ID^.Name, ' was never defined.');
  724.         end;
  725.         ID := ID^.Next;
  726.         end;
  727.     end;
  728.     CB := CB^.Previous;
  729.     end;
  730. end;
  731.  
  732. Procedure DumpRefs;
  733.  
  734. {
  735.     This routine makes all the external references necessary.
  736. }
  737.  
  738. var
  739.     CB        : BlockPtr;
  740.     ID        : IDPtr;
  741.     i        : Integer;
  742. begin
  743.     writeln(OutFile);
  744.     CB := CurrentBlock;
  745.     while CB <> nil do begin
  746.     for i := 0 to Hash_Size do begin
  747.         ID := CB^.Table[i];
  748.         while ID <> nil do begin
  749.         if ID^.Storage = st_external then
  750.             writeln(OutFile, "\tXREF\t_", ID^.Name);
  751.         ID := ID^.Next;
  752.         end;
  753.     end;
  754.     CB := CB^.Previous;
  755.     end
  756. end;
  757.  
  758. Procedure SearchReserved;
  759.  
  760. {
  761.     This just does a binary chop search of the list of reserved
  762. words.
  763. }
  764.  
  765. var
  766.     top,
  767.     middle,
  768.     bottom    : Symbols;
  769.     compare    : Short;
  770. begin
  771.     Bottom := And1;
  772.     Top := LastReserved;
  773.     while Bottom <= Top do begin
  774.     middle := Symbols((Byte(bottom) + Byte(top)) div 2);
  775.     Compare := stricmp(Reserved[Middle], SymText);
  776.     if Compare = 0 then begin
  777.         CurrSym := Middle;
  778.         Return;
  779.     end else if Compare < 0 then
  780.         Bottom := Succ(Middle)
  781.     else
  782.         Top := Pred(Middle);
  783.     end;
  784.     CurrSym := Ident1;
  785. end;
  786.  
  787. Procedure ReadWord;
  788.  
  789. {
  790.     This reads a Pascal identifier into symtext.
  791. }
  792.  
  793. var
  794.     ptr        : string;
  795. begin
  796.     ptr := symtext;
  797.     repeat
  798.     Ptr^ := CurrentChar;
  799.     Ptr := String(Integer(Ptr) + 1);
  800.     ReadChar;
  801.     until not AlphaNumeric(CurrentChar);
  802.     Ptr^ := chr(0);
  803.     SearchReserved;
  804. end;
  805.  
  806. Function DigVal(c : Char) : Integer;
  807. begin
  808.     DigVal := Ord(c) - Ord('0');
  809. end;
  810.  
  811. Procedure ReadNumber;
  812.  
  813. {
  814.     This routine reads a literal integer.  Note that _ can be used.
  815. }
  816.  
  817. var
  818.     Divider : Real;
  819.     Fraction : Real;
  820. begin
  821.     SymLoc := 0;
  822.     While isdigit(CurrentChar) do begin
  823.     SymLoc := (SymLoc * 10) + DigVal(CurrentChar);
  824.     ReadChar;
  825.     if CurrentChar = '_' then
  826.         ReadChar;
  827.     end;
  828.     CurrSym := Numeral1;
  829.     if (CurrentChar = '.') and isdigit(NextChar()) then begin { It's real! }
  830.     ReadChar; { skip the . }
  831.     RealValue := Float(SymLoc);
  832.     Divider := 1.0;
  833.     Fraction := 0.0;
  834.     while isdigit(CurrentChar) do begin
  835.         Fraction := Fraction * 10.0 + Float(DigVal(CurrentChar));
  836.         Divider := Divider * 10.0;
  837.         ReadChar;
  838.     end;
  839.     RealValue := RealValue + Fraction / Divider;
  840.     CurrSym := RealNumeral1;
  841.     end;
  842. end;
  843.  
  844. Procedure ReadHex;
  845.  
  846. {
  847.     readhex() reads a hexadecimal number.
  848. }
  849.  
  850. var
  851.     rc    : integer;
  852.     Count : Short;
  853. begin
  854.     ReadChar;
  855.     symloc := 0;
  856.     Count := 0;
  857.     rc := ord(toupper(currentchar));
  858.     while isdigit(currentchar) or
  859.       ((rc >= ord('A')) and (rc <= ord('F'))) do begin
  860.     Inc(Count);
  861.     SymLoc := SymLoc shl 4;
  862.     if isdigit(currentchar) then
  863.         symloc := symloc + ord(currentchar) - ord('0')
  864.     else
  865.         symloc := symloc + rc - ord('A') + 10;
  866.     ReadChar;
  867.     rc := ord(toupper(currentchar));
  868.     end;
  869.  
  870.     if Count = 0 then
  871.     Error("No hexadecimal digits")
  872.     else if Count > 8 then
  873.     Error("Constant out of range (more than 32 bits)");
  874.  
  875.     currsym := numeral1;
  876. end;
  877.  
  878.  
  879. Procedure ReadBinary;
  880. {
  881.     Reads a binary number, of the form %[0|1]*
  882. }
  883. var
  884.     Count : Short;
  885. begin
  886.     ReadChar; { Read past the % }
  887.     SymLoc := 0;
  888.     Count := 0;
  889.     while (CurrentChar = '0') or (CurrentChar = '1') do begin
  890.     Inc(Count);
  891.     SymLoc := (SymLoc shl 1) + DigVal(CurrentChar);
  892.     ReadChar;
  893.     end;
  894.  
  895.     if Count = 0 then
  896.     Error("No binary digits")
  897.     else if Count > 32 then
  898.     Error("Constant out of range (more than 32 bits)");
  899.  
  900.     CurrSym := Numeral1;
  901. end;
  902.  
  903. {
  904. Procedure ReadString;
  905. var
  906.     Delim : Char;
  907. begin
  908.     InStringLength := 0;
  909.     Delim := CurrentChar;
  910.     ReadChar;
  911.     repeat
  912.     if CurrentChar = Delim then begin
  913.         ReadChar;
  914.         if (CurrentChar = Delim) and (Delim = '\'') then begin
  915.         Insert('\'');
  916.         ReadChar;
  917.         end else
  918.         Quit := True;
  919.     end else if CurrentChar = '#' then begin
  920.         ReadChar;
  921.         case CurrentChar of
  922.           '0'..'9'  : ReadNumber;
  923.           '$'    : ReadHex;
  924.           '%'    : ReadBinary;
  925.         else begin
  926.              Error("Expecting an integer");
  927.              SymLoc := 0;
  928.              CurrSym := Numeral1;
  929.          end;
  930.         end;
  931.         if CurrSym <> Numeral1 then
  932.         Error("Expecting an integer");
  933.         if SymLoc > 255 then
  934.         Error("Constant out of range");
  935.         Insert(Chr(SymLoc));
  936.     end else if CurrentChar = Chr(10) then begin
  937.         Error("String exceeds line");
  938.         Quit := True;
  939.     end else if CurrentChar = '\\' then begin
  940.         ReadChar;
  941.         case CurrentChar of
  942.           'n' : Insert(Chr(10));
  943.           't' : Insert(Chr(9));
  944.           '0' : Insert(Chr(0));
  945.           'b' : Insert(Chr(8));
  946.           'e' : Insert(Chr(27));
  947.           'c' : Insert(Chr($9B));
  948.           'a' : Insert(Chr(7));
  949.           'f' : Insert(Chr(12));
  950.           'r' : Insert(Chr(13));
  951.           'v' : Insert(Chr(11));
  952.         else
  953.         Insert(CurrentChar);
  954.         end;
  955.         ReadChar;
  956.     end else begin
  957.         Insert(CurrentChar);
  958.         ReadChar;
  959.     end;
  960.     until Quit;
  961.     if InStringLength = 1 then begin
  962.     SymLoc := InString[0];
  963.     CurrSym := Char1;
  964.     end else if Delim = '"' then
  965.     CurrSym := Quote1
  966.     else
  967.     CurrSym := Apostrophe1;
  968. end;
  969. }
  970.  
  971. Procedure WriteHex(num : integer);
  972.  
  973. {
  974.     This writes full 32 bit hexadecimal numbers.
  975. }
  976.  
  977. var
  978.     numary  : array [1..8] of char;
  979.     pos     : integer;
  980.     ch      : Short;
  981. begin
  982.     pos := 8;
  983.     while (num <> 0) and (pos > 0) do begin
  984.     ch := num and 15;
  985.     if ch < 10 then
  986.         numary[pos] := chr(ch + ord('0'))
  987.     else
  988.         numary[pos] := chr(ch + ord('A') - 10);
  989.     pos := pos - 1;
  990.     num := num shr 4;
  991.     end;
  992.     if pos = 8 then begin
  993.     pos := 7;
  994.     numary[8] := '0';
  995.     end;
  996.     write(OutFile, '$');
  997.     for num := pos + 1 to 8 do
  998.     write(OutFile, numary[num]);
  999. end;
  1000.  
  1001. Procedure NextSymbol;
  1002.  
  1003. {
  1004.     This is the workhorse lexical analysis routine.  It sets
  1005. currsym to the appropriate symbol number, sets symtext equal to
  1006. whatever identifier is read, and symloc to the value of a literal
  1007. integer.
  1008. }
  1009.  
  1010. begin
  1011.     Blanks;
  1012.     ErrorPtr := EQEnd;
  1013.     if EndOfFile then begin
  1014.     CurrentChar := Chr(0);
  1015.     CurrSym := EndText1; { I don't think this routine is ever hit }
  1016.     Return;
  1017.     end;
  1018.     if Alpha(CurrentChar) then
  1019.     readword
  1020.     else if isdigit(currentchar) then
  1021.     readnumber
  1022.     else begin
  1023.     case CurrentChar of
  1024.       '[' : begin
  1025.             CurrSym:= leftbrack1;
  1026.             ReadChar;
  1027.         end;
  1028.       ']' : begin
  1029.             CurrSym:= rightbrack1;
  1030.             ReadChar;
  1031.         end;
  1032.       '(' : begin
  1033.             CurrSym:= leftparent1;
  1034.             ReadChar;
  1035.         end;
  1036.       ')' : begin
  1037.             CurrSym:= rightparent1;
  1038.             ReadChar;
  1039.         end;
  1040.       '+' : begin
  1041.             CurrSym := plus1;
  1042.             ReadChar;
  1043.         end;
  1044.       '-' : begin
  1045.             CurrSym := minus1;
  1046.             ReadChar;
  1047.         end;
  1048.       '*' : begin
  1049.             CurrSym:= asterisk1;
  1050.             ReadChar;
  1051.         end;
  1052.       '/' : begin
  1053.             CurrSym := RealDiv1;
  1054.             ReadChar;
  1055.         end;
  1056.       '<' : begin
  1057.             ReadChar;
  1058.             if CurrentChar = '=' then begin
  1059.             CurrSym := notgreater1;
  1060.             ReadChar;
  1061.             end else if currentchar = '>' then begin
  1062.             CurrSym := notequal1;
  1063.             ReadChar;
  1064.             end else
  1065.             CurrSym:= less1;
  1066.         end;
  1067.       '=' : begin
  1068.             CurrSym:= equal1;
  1069.             ReadChar;
  1070.         end;
  1071.       '>' : begin
  1072.             ReadChar;
  1073.             if CurrentChar = '=' then begin
  1074.             CurrSym:= notless1;
  1075.             ReadChar;
  1076.             end else
  1077.             CurrSym:= greater1;
  1078.         end;
  1079.       ':' : begin
  1080.             ReadChar;
  1081.             if CurrentChar = '=' then begin
  1082.             CurrSym:= Becomes1;
  1083.             ReadChar;
  1084.             end else
  1085.             CurrSym:= colon1;
  1086.         end;
  1087.       ',' : begin
  1088.             CurrSym:= comma1;
  1089.             ReadChar;    
  1090.         end;
  1091.       '.' : begin
  1092.             ReadChar;
  1093.             if CurrentChar = '.' then begin
  1094.             CurrSym:= DotDot1;
  1095.             ReadChar;
  1096.             end else
  1097.             CurrSym:= period1;
  1098.         end;
  1099.       ';' : begin
  1100.             CurrSym:= semicolon1;
  1101.             ReadChar;
  1102.         end;
  1103.       '\'': begin
  1104.             CurrSym:= apostrophe1;
  1105.             ReadChar;
  1106.         end;
  1107.       '"' : begin
  1108.             CurrSym:= quote1;
  1109.             ReadChar;
  1110.         end;
  1111.       '^' : begin
  1112.             CurrSym:= carat1;
  1113.             ReadChar;
  1114.         end;
  1115.       '@' : begin
  1116.             CurrSym := At1;
  1117.             ReadChar;
  1118.         end;
  1119.       '$' : ReadHex;
  1120.       '%' : ReadBinary;
  1121.      '\0' : CurrSym := EndText1;
  1122.     else begin
  1123.         Error("Unknown symbol.");
  1124.         ReadChar;
  1125.          end;
  1126.     end; { Case }
  1127.     end; { Else }
  1128. end;
  1129.